package edu.ncsu.monopoly.logic.entities;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;

import edu.ncsu.monopoly.logic.GameBoard;
import edu.ncsu.monopoly.logic.GameMaster;
import edu.ncsu.monopoly.logic.cells.Cell;
import edu.ncsu.monopoly.logic.cells.JailCell;
import edu.ncsu.monopoly.logic.cells.PropertyCell;
import edu.ncsu.monopoly.logic.cells.RailRoadCell;
import edu.ncsu.monopoly.logic.cells.UtilityCell;


public class Player {
	//the key of colorGroups is the name of the color group.
	private Hashtable<String, Integer> colorGroups = new Hashtable<String, Integer>();
	private boolean inJail;
	private int money;
	private String name;

	private Cell position;
	private ArrayList<Cell> ownedCells = new ArrayList<Cell>();
	
	public Player(int money) {
		GameBoard gb = GameMaster.instance().getGameBoard();
		inJail = false;
		if(gb != null) {
			position = gb.getGoCell();
		}
		this.money = money;
	}
	
    public void buyProperty(Cell cell, int amount) {
    	cell.setOwner(this);
    	ownedCells.add(cell);
        colorGroups.put(
                cell.getColorGroup(), 
                new Integer(getPropertyNumberForColor(cell.getColorGroup())+1));

        decreaseMoney(amount);
    }
	
	public boolean canBuyHouse() {
		return (getMonopolies().length != 0);
	}
	
	public boolean hasProperty(String property) {
		ArrayList<Cell> ownedProperties = getOwnedProperties();
		for(int i=0;i<ownedProperties.size();i++) {
			PropertyCell propertyCell = (PropertyCell)ownedProperties.get(i);
			if(propertyCell.getName().equals(property)) {
				return true;
			}
		}
		return false;		
	}
	
	public ArrayList<Cell> getOwnedProperties(){
		return queryOwnedCells(PropertyCell.class);
	}
	
	private ArrayList<Cell> queryOwnedCells(Class<? extends Cell> aClass) {
	   ArrayList<Cell> result = new ArrayList<Cell>();
	   for(int index = 0; index < ownedCells.size(); index++){
		   Cell cell = ownedCells.get(index);		   
		   if(cell.getClass().equals(aClass)){
			   result.add(cell);
		   }
	   }
	   
	   return result;
	}
	
	private void removeAllOwnedCellsOfType(Class<? extends Cell> aClass) {
	   for(int index = 0; index < ownedCells.size(); index++){
		   Cell cell = ownedCells.get(index);		   
		   if(cell.getClass().equals(aClass)){
			   ownedCells.remove(index);
		   }
	   }
	}
	
	public void giveAllPropertiesTo(Player player) {
		for(int i = 0; i < getPropertiesCount(); i++ ) {
			PropertyCell propertyCell = getProperty(i);
			propertyCell.setOwner(player);
			if(player == null) {
				propertyCell.setAvailable(true);
				propertyCell.setNumberOfHouses(0);
			}
			else {
				player.ownedCells.add(propertyCell);
				colorGroups.put(
						propertyCell.getColorGroup(), 
						new Integer(getPropertyNumberForColor(propertyCell.getColorGroup())+1));
			}
		}
		removeAllOwnedCellsOfType(PropertyCell.class);
	}
	
	public Cell[] getAllOwnedCells() {
		return (Cell[])ownedCells.toArray(new Cell[ownedCells.size()]);
	}
	
	public int getMoney() {
		return this.money;
	}
	
	public String[] getMonopolies() {
		ArrayList<String> monopolies = new ArrayList<String>();
		Enumeration<String> colors = colorGroups.keys();
		while(colors.hasMoreElements()) {
			String color = (String)colors.nextElement();
            if(!(color.equals(RailRoadCell.COLOR_GROUP)) && !(color.equals(UtilityCell.COLOR_GROUP))) {
    			Integer num = (Integer)colorGroups.get(color);
    			GameBoard gameBoard = GameMaster.instance().getGameBoard();
    			if(num.intValue() == gameBoard.getPropertyNumberForColor(color)) {
    				monopolies.add(color);
    			}
            }
		}
		return (String[])monopolies.toArray(new String[monopolies.size()]);
	}

	public String getName() {
		return name;
	}

	public void getOutOfJail() {
		money -= JailCell.BAIL;
		if(isBankrupt()) {
			money = 0;
			giveAllPropertiesTo(null);
		}
		inJail = false;
		GameMaster.instance().updateGUI();
	}

	public Cell getPosition() {
		return this.position;
	}
		
	public PropertyCell getProperty(int index) {
		return (PropertyCell)queryOwnedCells(PropertyCell.class).get(index);
	}
	
	public int getPropertiesCount() {
		return queryOwnedCells(PropertyCell.class).size();
	}

	private int getPropertyNumberForColor(String name) {
		Integer number = (Integer)colorGroups.get(name);
		if(number != null) {
			return number.intValue();
		}
		return 0;
	}

	public boolean isBankrupt() {
		return money <= 0;
	}

	public boolean isInJail() {
		return inJail;
	}

	public int getRailRoadCellsCount() {
		return getPropertyNumberForColor(RailRoadCell.COLOR_GROUP);
	}

	public int getUtilityCellsCount() {
		return getPropertyNumberForColor(UtilityCell.COLOR_GROUP);
	}
	
	public void payRentTo(Player owner, int rentValue) {
		if(money < rentValue) {
			owner.money += money;
			money -= rentValue;
		}
		else {
			money -= rentValue;
			owner.money +=rentValue;
		}
		if(isBankrupt()) {
			money = 0;
			giveAllPropertiesTo(owner);
		}
	}
	
	public void purchase() {
		if(getPosition().isAvailable()) {
			Cell c = getPosition();
			c.setAvailable(false);
			buyProperty(c, c.getPrice());
		}
	}
	
	public void purchaseHouse(String selectedMonopoly, int houses) {
		GameBoard gb = GameMaster.instance().getGameBoard();
		PropertyCell[] cells = gb.getPropertiesInMonopoly(selectedMonopoly);
		if((money >= (cells.length * (cells[0].getHousePrice() * houses)))) {
			for(int i = 0; i < cells.length; i++) {
				int newNumber = cells[i].getHousesCount() + houses;
				if (newNumber <= 5) {
					cells[i].setNumberOfHouses(newNumber);
					this.decreaseMoney(cells[i].getHousePrice() * houses);
					GameMaster.instance().updateGUI();
				}
			}
		}
	}

    public void sellProperty(Cell property, int amount) {
        property.setOwner(null);
        ownedCells.remove(property);
        increaseMoney(amount);
    }


	public void setInJail(boolean inJail) {
		this.inJail = inJail;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setPosition(Cell newPosition) {
		this.position = newPosition;
	}

    public String toString() {
        return name;
    }
    
    public void resetProperty() {
    	ownedCells = new ArrayList<Cell>();
	}
    
    public void increaseMoney(int money) {
    	this.money += money;
    }
    
    public void decreaseMoney(int money) {
    	this.money -= money;
    }
}
